{{!

  Copyright (c) Facebook, Inc. and its affiliates.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

      http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

}}

    pub mod {{service:snake}} {{>lib/block}}{{!
        }}{{#service:rustFunctions}}{{^function:returns_streams?}}

        #[derive(Clone, Debug)]
        pub enum {{function:upcamel}}Exn {
            Success({{#function:returnType}}{{>lib/type}}{{/function:returnType}}),{{!
            }}{{#function:exceptions}}
            {{field:rust_name}}({{#field:type}}{{>lib/type}}{{/field:type}}),{{!
            }}{{/function:exceptions}}
            ApplicationException(::fbthrift::ApplicationException),
        }{{!
        }}{{#function:uniqueExceptions}}

        impl ::std::convert::From<{{#field:type}}{{>lib/type}}{{/field:type}}> for {{function:upcamel}}Exn {
            fn from(exn: {{#field:type}}{{>lib/type}}{{/field:type}}) -> Self {
                {{function:upcamel}}Exn::{{field:rust_name}}(exn)
            }
        }{{!
        }}{{/function:uniqueExceptions}}

        impl ::std::convert::From<::fbthrift::ApplicationException> for {{function:upcamel}}Exn {
            fn from(exn: ::fbthrift::ApplicationException) -> Self {
                {{function:upcamel}}Exn::ApplicationException(exn)
            }
        }

        impl ::fbthrift::GetTType for {{function:upcamel}}Exn {
            const TTYPE: ::fbthrift::TType = ::fbthrift::TType::Struct;
        }

        impl<P> ::fbthrift::Serialize<P> for {{function:upcamel}}Exn
        where
            P: ::fbthrift::ProtocolWriter,
        {
            fn write(&self, p: &mut P) {
                p.write_struct_begin("{{function:upcamel}}");
                match self {
                    {{function:upcamel}}Exn::Success(inner) => {
                        p.write_field_begin(
                            "Success",
                            {{#function:returnType}}{{>lib/ttype}}{{/function:returnType}},
                            0i16,
                        );
                        inner.write(p);
                        p.write_field_end();
                    }{{!
                    }}{{#function:exceptions}}
                    {{function:upcamel}}Exn::{{field:rust_name}}(inner) => {
                        p.write_field_begin(
                            "{{field:name}}",
                            {{#field:type}}{{>lib/ttype}}{{/field:type}},
                            {{field:key}},
                        );
                        inner.write(p);
                        p.write_field_end();
                    }{{!
                    }}{{/function:exceptions}}
                    {{function:upcamel}}Exn::ApplicationException(_) => panic!(
                        "Bad union Alt field {} id {}",
                        "ApplicationException",
                        -2147483648i32,
                    ),
                }
                p.write_field_stop();
                p.write_struct_end();
            }
        }

        impl<P> ::fbthrift::Deserialize<P> for {{function:upcamel}}Exn
        where
            P: ::fbthrift::ProtocolReader,
        {
            fn read(p: &mut P) -> ::anyhow::Result<Self> {
                static RETURNS: &[::fbthrift::Field] = &[
                    {{#function:returns_by_name}}
                    ::fbthrift::Field::new("{{field:name}}", {{#field:type}}{{>lib/ttype}}{{/field:type}}, {{field:key}}),
                    {{/function:returns_by_name}}
                ];
                let _ = p.read_struct_begin(|_| ())?;
                let mut once = false;
                let mut alt = {{!
                    }}{{#function:void?}}{{!
                        }}{{function:upcamel}}Exn::Success(()){{!
                    }}{{/function:void?}}{{!
                    }}{{^function:void?}}::std::option::Option::None{{/function:void?}}{{!
                }};
                loop {
                    let (_, fty, fid) = p.read_field_begin(|_| (), RETURNS)?;
                    match ((fty, fid as ::std::primitive::i32), once) {
                        ((::fbthrift::TType::Stop, _), _) => {
                            p.read_field_end()?;
                            break;
                        }
                        (({{#function:returnType}}{{>lib/ttype}}{{/function:returnType}}, 0i32), false) => {
                            once = true;
                            alt = {{!
                                }}{{^function:void?}}::std::option::Option::Some({{/function:void?}}{{!
                                }}{{function:upcamel}}Exn::Success(::fbthrift::Deserialize::read(p)?){{!
                                }}{{^function:void?}}){{/function:void?}}{{!
                            }};
                        }{{!
                        }}{{#function:exceptions}}
                        (({{#field:type}}{{>lib/ttype}}{{/field:type}}, {{field:key}}), false) => {
                            once = true;
                            alt = {{!
                                }}{{^function:void?}}::std::option::Option::Some({{/function:void?}}{{!
                                }}{{function:upcamel}}Exn::{{field:rust_name}}(::fbthrift::Deserialize::read(p)?){{!
                                }}{{^function:void?}}){{/function:void?}}{{!
                            }};
                        }{{!
                        }}{{/function:exceptions}}
                        ((ty, _id), false) => p.skip(ty)?,
                        ((badty, badid), true) => return ::std::result::Result::Err(::std::convert::From::from(
                            ::fbthrift::ApplicationException::new(
                                ::fbthrift::ApplicationExceptionErrorCode::ProtocolError,
                                format!(
                                    "unwanted extra union {} field ty {:?} id {}",
                                    "{{function:upcamel}}Exn",
                                    badty,
                                    badid,
                                ),
                            )
                        )),
                    }
                    p.read_field_end()?;
                }
                p.read_struct_end()?;{{!
                }}{{#function:void?}}
                ::std::result::Result::Ok(alt){{!
                }}{{/function:void?}}{{!
                }}{{^function:void?}}
                alt.ok_or_else(||
                    ::fbthrift::ApplicationException::new(
                        ::fbthrift::ApplicationExceptionErrorCode::MissingResult,
                        format!("Empty union {}", "{{function:upcamel}}Exn"),
                    )
                    .into(),
                ){{!
                }}{{/function:void?}}
            }
        }{{!
        }}{{/function:returns_streams?}}{{/service:rustFunctions}}
    }
    {{!newline}}
